<?php

namespace App\Console\Commands\Cruise;

use App\Enums\OpenShop\InvestmentPromotion\SignOrderEnum;
use App\Models\Cruise\CruiseCheckSelfDetailModel;
use App\Models\Cruise\CruiseCheckSelfTaskModel;
use App\Models\Cruise\CruiseOrderModel;
use App\Models\Cruise\CruiseTemplateModel;
use App\Models\Cruise\ShopSelfCheckNotifyConfigModel;
use App\Models\Shop\ShopModel;
use App\Models\System\SystemNotifyCenterModel;
use App\Remote\Rms\RmsUserRemote;
use App\Service\Common\SmsService;
use App\Service\Cruise\Merchant\ShopSelfCheckNotifyConfigService;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class ShopSelfCheckNotify extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'cruise:shop-self-check-notify {--today=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '门店自检提醒';

    /**
     * @var Carbon null
     */
    protected $carbon = null;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->setCurrent();
        $this->notify();
        return true;
    }

    public function setCurrent()
    {
        if ($today = $this->option('today')){
            $this->carbon = Carbon::createFromFormat('Y-m-d H:i:s',$today);
        } else {
            $this->carbon = Carbon::now();
        }
    }

    public function notify()
    {
        //
        $templates = CruiseTemplateModel::query()
                                        ->where(['type' => CruiseTemplateModel::TYPE_8])
                                        ->whereIn('sysTemplate',
                                            CruiseTemplateModel::TEMPLATE_TYPES[CruiseTemplateModel::TYPE_8])
                                        ->get()
                                        ->keyBy('id');

        //
        $checkTasks = CruiseCheckSelfTaskModel::query()
                                              ->where("isDeleted", 0)
                                              ->where("taskStartTime", "<=", time())
                                              ->where("taskEndTime", ">", time())
                                              ->where('status', CruiseCheckSelfTaskModel::STATUS_ON)
                                              ->where('templateType', CruiseTemplateModel::TYPE_8)
                                              ->whereIn('templateId', array_keys($templates->toArray()))
                                              ->get()
                                              ->keyBy('id');

        $detail = CruiseCheckSelfDetailModel::query()
                                            ->where('updatedAt', '>', strtotime('-1 day'))
                                            ->where('executeEndTime', '>', $this->carbon->timestamp)
                                            ->first();

        //获取自检任务列表
        CruiseCheckSelfDetailModel::query()
                                  ->leftJoin(
                                      'cruise_order as order',
                                      'cruise_check_self_detail.cruiseOrderId',
                                      '=', 'order.id'
                                  )
                                  ->where([
                                      //门店自检
                                      ['cruise_check_self_detail.id','>',$detail->id],
                                      ['templateType', '=', CruiseTemplateModel::TYPE_8],
                                      ['cruiseOrderId', '>', 0],
                                      ['order.isDeleted', '=', 0],
                                  ])
                                  ->whereIn('order.status',
                                      [CruiseOrderModel::STATUS_INIT, CruiseOrderModel::STATUS_NOT_SUBMIT]
                                  )
                                  ->whereIn('taskId', array_keys($checkTasks->toArray()))
                                  ->select([
                                      'cruise_check_self_detail.*',
                                      'order.status as oStatus',
                                      'order.templateId'
                                  ])
                                  ->chunk(100, function ($detailList) use ($templates, $checkTasks) {

                                      $shopIds      = collect($detailList)->pluck('shopId')->unique()->toArray();
                                      $shopInfoList = $this->getShopInfoAndNotifyConfig($shopIds);

                                      $userListKeyShopId = RmsUserRemote::usersInShops($shopIds);

                                      if (empty($userListKeyShopId)) {
                                          self::recordLog('rms获取用户信息失败');
                                          return;
                                      }

                                      foreach ($detailList as $detailItem) {
                                          $shopId = $detailItem->shopId;
                                          //任务属于哪个类型
                                          $sysTemplate  = $templates[$detailItem->templateId]->sysTemplate;

                                          //是否在发送中
                                          if ($this->isNotifyProcessing($detailItem->id,$sysTemplate)) {
                                              self::recordLog('正在发送中或已经发送过', ['detailId'=>$detailItem->id]);
                                              continue;
                                          }

                                          $shopInfo = $shopInfoList[$shopId] ?? null;

                                          //提醒配置
                                          if (empty($shopInfo)) {
                                              self::recordLog('shopInfo为空',['shopId'=>$shopId]);
                                              continue;
                                          }

                                          //获取配置信息
                                          $notifyConfig = $shopInfo->configId
                                              ? [
                                                  'notifySwitch'       => $shopInfo->notifySwitch,
                                                  'notifyRoles'        => json_decode($shopInfo->notifyRoles, 1),
                                                  'notifyType'         => json_decode($shopInfo->notifyType, 1),
                                                  'kdNotifyTimeMap'    => $shopInfo->kdNotifyTimeMap,
                                                  'sdNotifyTimeMap'    => $shopInfo->sdNotifyTimeMap,
                                                  'weekNotifyTimeMap'  => $shopInfo->weekNotifyTimeMap,
                                                  'monthNotifyTimeMap' => $shopInfo->monthNotifyTimeMap,
                                              ]
                                              : ShopSelfCheckNotifyConfigModel::getDefaultConfig();

                                          if ($notifyConfig['notifySwitch'] == ShopSelfCheckNotifyConfigModel::SWITCH_CLOSE) {
                                              self::recordLog(
                                                  '门店已关闭推送开关', $shopInfo->toArray()
                                              );
                                              continue;
                                          }

                                          $businessTime = ShopSelfCheckNotifyConfigService::getShopBusinessTimeChangeByDb(
                                              $shopInfo->startAt ?: ShopSelfCheckNotifyConfigModel::SHOP_BUSINESS_OPEN_DEFAULT,
                                              $shopInfo->endAt ?: ShopSelfCheckNotifyConfigModel::SHOP_BUSINESS_CLOSE_DEFAULT
                                          );

                                          $canNotify = false;
                                          switch ($sysTemplate) {
                                              case CruiseTemplateModel::SYS_TEMPLATE_SELF_OPEN:
                                                  $canNotify = ShopSelfCheckNotifyConfigModel::canPushByNotifyTimeMap(
                                                          $notifyConfig['kdNotifyTimeMap'],
                                                          $this->carbon
                                                      ) && ShopSelfCheckNotifyConfigModel::canPushByBusinessTime(
                                                          $sysTemplate,
                                                          $notifyConfig['kdNotifyTimeMap'],
                                                          $this->carbon->timestamp,
                                                          $businessTime['startAt'], $businessTime['endAt']
                                                      );
                                                  break;
                                              case CruiseTemplateModel::SYS_TEMPLATE_SELF_CLOSE:
                                                  $canNotify = ShopSelfCheckNotifyConfigModel::canPushByNotifyTimeMap(
                                                          $notifyConfig['sdNotifyTimeMap'],
                                                          $this->carbon
                                                      ) && ShopSelfCheckNotifyConfigModel::canPushByBusinessTime(
                                                          $sysTemplate,
                                                          $notifyConfig['sdNotifyTimeMap'],
                                                          $this->carbon->timestamp,
                                                          $businessTime['startAt'], $businessTime['endAt']
                                                      );
                                                  break;
                                              case CruiseTemplateModel::SYS_TEMPLATE_SELF_WEEK:
                                                  $canNotify = ShopSelfCheckNotifyConfigModel::canPushByNotifyTimeMap(
                                                          $notifyConfig['weekNotifyTimeMap'],
                                                          $this->carbon
                                                      ) && ShopSelfCheckNotifyConfigModel::canPushByBusinessTime(
                                                          $sysTemplate,
                                                          $notifyConfig['weekNotifyTimeMap'],
                                                          $this->carbon->timestamp,
                                                          $businessTime['startAt'], $businessTime['endAt']
                                                      );
                                                  break;
                                              case CruiseTemplateModel::SYS_TEMPLATE_SELF_MONTH:
                                                  $canNotify = ShopSelfCheckNotifyConfigModel::canPushByNotifyTimeMap(
                                                          $notifyConfig['monthNotifyTimeMap'],
                                                          $this->carbon
                                                      ) && ShopSelfCheckNotifyConfigModel::canPushByBusinessTime(
                                                          $sysTemplate,
                                                          $notifyConfig['monthNotifyTimeMap'],
                                                          $this->carbon->timestamp,
                                                          $businessTime['startAt'], $businessTime['endAt']
                                                      );
                                                  break;
                                          }
                                          if (!$canNotify) {
                                              self::recordLog('不满足推送时间条件',[
                                                  'shopId'=>$shopId,
                                                  'detailId'=>$detailItem->id,
                                                  'templateId'=>$detailItem->templateId,
                                                  'sysTemplate'=>$sysTemplate,
                                                  'notifyConfig'=>$notifyConfig,
                                                  'time'=>$this->carbon->timestamp,
                                                  'startAt'=>$businessTime['startAt'],
                                                  'endAt'=>$businessTime['endAt'],
                                              ]);
                                              continue;
                                          }

                                          $taskInfo = $checkTasks[$detailItem->taskId] ?? null;
                                          if (empty($taskInfo)) {
                                              self::recordLog('获取的任务为空',[
                                                  'shopId'=>$shopId,
                                                  'detailId'=>$detailItem->id,
                                              ]);
                                              continue;
                                          }

                                          //是否在可执行自检的时间内
                                          if (!ShopSelfCheckNotifyConfigModel::canPushByTaskExecTime(
                                              $this->carbon->timestamp, $taskInfo->executeStartHis,
                                              $taskInfo->executeEndHis
                                          )) {
                                              self::recordLog('不在自检时间内',[
                                                  'shopId'=>$shopId,
                                                  'detailId'=>$detailItem->id,
                                                  'time'=>$this->carbon->timestamp,
                                                  'executeStartHis'=>$taskInfo->executeStartHis,
                                                  'executeEndHis'=>$taskInfo->executeEndHis,
                                              ]);
                                              continue;
                                          }

                                          if (empty($notifyConfig['notifyRoles']) || empty($notifyConfig['notifyType'])) {
                                              self::recordLog('推送角色或推送类型为空',[
                                                  'shopId'=>$shopId,
                                                  'detailId'=>$detailItem->id,
                                                  'notifyConfig'=>$notifyConfig
                                              ]);
                                              continue;
                                          }

                                          $roleConfig = $userListKeyShopId['roleConfig'];
                                          $shopUsers  = $userListKeyShopId['list'][$shopId] ?? [];
                                          if (empty($shopUsers)) {
                                              self::recordLog('获取的用户信息为空,无法推送',[
                                                  'userListKeyShopId'=>$userListKeyShopId,
                                                  'shopId'=>$shopId,
                                                  'detailId'=>$detailItem->id
                                              ]);
                                              continue;
                                          }

                                          $pushUsers = self::getPushUsers(
                                              $notifyConfig['notifyRoles'], $roleConfig, $shopUsers
                                          );


                                          if (empty($pushUsers)) {
                                              self::recordLog('无符合推送的角色用户',[
                                                  'shopId'=>$shopId,
                                                  'notifyRoles'=>$notifyConfig['notifyRoles'],
                                                  'roleConfig'=>$roleConfig,
                                                  'shopUsers'=>$shopUsers
                                              ]);
                                              continue;
                                          }

                                          if ($this->isNotifyProcessing($detailItem->id,$sysTemplate)){
                                              self::recordLog('即将发送时被抢占',['detailId'=>$detailItem->id]);
                                              continue;
                                          }

                                          //缓存,执行时间后
                                          $this->setNotifyProcessing(
                                              $detailItem->id, $taskInfo->executeStartHis, $taskInfo->executeEndHis
                                          );
                                          CruiseCheckSelfDetailModel::query()
                                                                    ->where(['id' => $detailItem->id])
                                                                    ->update([
                                                                        'updatedAt'  => $this->carbon->timestamp,
                                                                        'notifyTime' => $this->carbon->timestamp
                                                                    ]);

                                          $taskDate = date('m月d日', strtotime($detailItem->date));
                                          self::recordLog('推送发送中',['detailId'=>$detailItem->id]);
                                          if (in_array(
                                              ShopSelfCheckNotifyConfigModel::NOTIFY_TYPE_APP,
                                              $notifyConfig['notifyType']
                                          )) {
                                              $popEffectiveInfo = self::popEffectiveInfo(
                                                  $detailItem->executeStartTime, $detailItem->executeEndTime
                                              );
                                              //获取门店店员
                                              $notify = \App\Service\System\SystemNotifyService::save(
                                                  false,
                                                  $title = '自检提醒',
                                                  SystemNotifyCenterModel::NOTIFY_TYPE_3,
                                                  SystemNotifyCenterModel::NOTIFY_TARGET_1,
                                                  '',
                                                  $title,
                                                  config('webUrl.notify_web_cdn_url')
                                                  . "#/pages/shop-check/list/main",
                                                  SystemNotifyCenterModel::METHOD_TYPE_AUTOMATIC,
                                                  self::generateAppPushSummary($taskInfo,$detailItem),
                                                  '',
                                                  SystemNotifyCenterModel::IS_POPUP_ON,
                                                  1,
                                                  0,[],1,
                                                  $popEffectiveInfo['popEffectiveDay'],'',0,0,
                                                  $popEffectiveInfo['popEffectiveTime']
                                              );
                                              \App\Service\System\SystemNotifyService::recordLog($notify, '自检提醒');
                                              \App\Service\System\SystemNotifyService::preSend(
                                                  $notify->id,
                                                  array_keys($pushUsers)
                                              );
                                          }

                                          //短信
                                          if (in_array(
                                              ShopSelfCheckNotifyConfigModel::NOTIFY_TYPE_SMG,
                                              $notifyConfig['notifyType']
                                          )) {
                                              foreach ($pushUsers as $pushUser) {
                                                  $mobile = $pushUser['userInfo']['mobile'] ?? '';
                                                  if (empty($mobile)) {
                                                      continue;
                                                  }

                                                  try{
                                                      (new SmsService())->aliyunSend(
                                                          $mobile,
                                                          config('sms.template.shopSelfCheckNotify'),
                                                          [
                                                              'date'     => $taskDate,
                                                              'shopCode' => $shopInfo->shopCode,
                                                              'taskName' => $taskInfo->name,
                                                          ]
                                                      );
                                                  } catch (\Exception $exception){
                                                      self::recordLog('推送短信失败:'.$exception->getMessage());
                                                  }
                                              }
                                          }
                                      }
                                  });
    }

    public function getShopInfoAndNotifyConfig($shopIds)
    {
        $configs = ShopSelfCheckNotifyConfigModel::query()
                                                 ->whereIn('shopId', $shopIds)
                                                 ->get()
                                                 ->keyBy('shopId');
        return ShopModel::query()
                        ->whereIn('id', $shopIds)
                        ->select([
                            'id',
                            'startAt',
                            'endAt',
                            'name',
                            'shopCode'
                        ])
                        ->get()
                        ->map(function ($item) use ($configs) {
                            $config = $configs[$item->id] ?? null;

                            $item->configId           = $config ? $config->id : null;
                            $item->notifySwitch       = $config ? $config->notifySwitch : null;
                            $item->notifyRoles        = $config ? $config->notifyRoles : null;
                            $item->notifyType         = $config ? $config->notifyType : null;
                            $item->kdNotifyTimeMap    = $config ? $config->kdNotifyTimeMap : null;
                            $item->sdNotifyTimeMap    = $config ? $config->sdNotifyTimeMap : null;
                            $item->weekNotifyTimeMap  = $config ? $config->weekNotifyTimeMap : null;
                            $item->monthNotifyTimeMap = $config ? $config->monthNotifyTimeMap : null;
                            return $item;
                        })
                        ->keyBy('id');

    }

    public static function recordLog($msg, $context = [])
    {
        Log::info("门店自检推送:{$msg}", $context);
    }

    public static function cacheProcessingKey($taskDetailId)
    {
        return 'shopSelfCheckNotify:detailId:' . $taskDetailId;
    }

    public function isNotifyProcessing($taskDetailId,$sysTemplate)
    {
        $cache = Cache::get(self::cacheProcessingKey($taskDetailId)) ?: [];
        if (empty($cache)){
            return false;
        }
        //日检稳一手
        if (in_array(
            $sysTemplate,[CruiseTemplateModel::SYS_TEMPLATE_SELF_OPEN,CruiseTemplateModel::SYS_TEMPLATE_SELF_CLOSE]
        )){
            return true;
        }

        return date('Y-m-d',$cache['notifyTime']) == $this->carbon->format('Y-m-d');
    }

    public function setNotifyProcessing($taskDetailId, $executeStartHis, $executeEndHis)
    {
        $executeStartHisFormat = str_replace(':', '', $executeStartHis);
        $executeEndHisFormat   = str_replace(':', '', $executeEndHis);

        //
        $executeEndSec = strtotime(date("Ymd {$executeEndHisFormat}"));

        if ($executeStartHisFormat >= $executeEndHisFormat) {
            $executeEndSec = strtotime(date("Ymd {$executeEndHisFormat}")) + (24 * 60 * 60);
        }

        $cacheSec = $executeEndSec - time();

        Cache::put(self::cacheProcessingKey($taskDetailId), ['notifyTime'=>time()], 3*24*3600);

        return true;
    }

    public static function getPushUsers($selectedRoleConfig, $rmsRoleConfig, $shopUsers)
    {
        $selectedRoleMap = [
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_1 => $rmsRoleConfig['manager'] ?? '',
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_2 => $rmsRoleConfig['orderGoods'] ?? '',
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_3 => $rmsRoleConfig['employee'] ?? '',
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_4 => $rmsRoleConfig['cashier'] ?? '',
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_5 => $rmsRoleConfig['temporary'] ?? '',
            ShopSelfCheckNotifyConfigModel::NOTIFY_ROLE_6 => $rmsRoleConfig['show'] ?? '',
        ];

        $parseRoleIds = [];
        foreach ($selectedRoleConfig as $role) {
            $parseRoleIds[] = $selectedRoleMap[$role] ?? '';
        }

        $shopUsers = array_filter($shopUsers, function ($user) use ($parseRoleIds) {
            $roleIds = $user['roleIds'];
            return array_intersect($parseRoleIds, $roleIds) ? true : false;
        });
        return $shopUsers;
    }

    public static function popEffectiveInfo(int $executeStartTime, int $executeEndTime): array
    {
        $day = ceil(($executeEndTime - $executeStartTime) / 86400);

        return [
            'popEffectiveDay'  => (int)$day,
            'popEffectiveTime' => $executeEndTime
        ];
    }

    public static function generateAppPushSummary(
        CruiseCheckSelfTaskModel $taskInfo,
        CruiseCheckSelfDetailModel $detailItem
    ): string {
        $execEndTime = Carbon::createFromTimestamp($detailItem->executeEndTime);
        if ($execEndTime->isCurrentDay()) {
            $date = '今日' . $execEndTime->format('H:i');
        } else {
            $date = $execEndTime->format('m月d日H:i');
        }
        $name = vsprintf("%s(%s)",[
            $taskInfo->name,
            $detailItem->getExecuteDateText($taskInfo->rule)
        ]);
        return vsprintf("【%s】自检任务已生成，需在%s前完成，请注意", [
            $name,
            $date
        ]);
    }
}
